package com.jiepos.mpos.inter.fourelement.service.yuqiang;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.GeneralSecurityException;
import java.security.KeyManagementException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.jiepos.mpos.common.constant.SystemConstant;
import com.jiepos.mpos.common.entity.App_Log_Four_ElementsEntity;
import com.jiepos.mpos.core.util.DateUtil;
import com.jiepos.mpos.core.util.IDFactoryUtil;
import com.jiepos.mpos.core.util.PropertiesUtil;
import com.jiepos.mpos.core.util.StringUtils;
import com.jiepos.mpos.inter.fourelement.FourElements;
import com.jiepos.mpos.inter.fourelement.service.AbrFourElementsService;
import com.jiepos.mpos.inter.fourelement.service.IFourElementService;

/**
 * 四要素认证业务功能类
 * 
 * @ProjectName: [mpos1]
 * @Package com.jiepos.mpos.biz.fourelement.service
 * @author 肖志伟
 * @version 1.0
 * @since 2017年9月26日 下午3:37:43
 * @history（历次修订内容、修订人、修订时间等） @UpdateRemark [说明本次修改内容]
 * @Copyright (c) 2017 江苏杰博实信息技术有限公司
 */
@Service
public class YuQiangLogFourElementsService extends AbrFourElementsService implements IFourElementService {

	public final Logger log = LoggerFactory.getLogger(getClass());

	/**
	 * 超时时间
	 */

	private static final int TIMEOUT = 100000;

	/**
	 * 接口认证token
	 */
	private static String TOKEN = null;

	/**
	 * md5加密key
	 */
	private static String ENCRYPTKEY = null;

	/**
	 * 接口URL
	 */
	private static String URL = null;

	/**
	 * HTTP请求标识
	 */
	private static int PATHFLAT_HTTP = 1;

	/**
	 * https请求标识
	 */
	private static int PATHFLAT_HTTPS = 2;

	/**
	 * 四要素认证结果成功
	 */
	private final static String FOURELEMENTS_AUTH_CODE_SUCCESS = "60000";

	static {
		PropertiesUtil.getProperties("conf.properties");
		TOKEN = PropertiesUtil.getProperty(SystemConstant.FOURELEMENTS_INTERFACE_TOKEN);
		ENCRYPTKEY = PropertiesUtil.getProperty(SystemConstant.FOURELEMENTS_INTERFACE_SECRETKEY);
		URL = PropertiesUtil.getProperty(SystemConstant.FOURELEMENTS_INTERFACE_URL);
	}

	@SuppressWarnings("rawtypes")
	@Override
	public Map queryFourElement(FourElements elements, Map paramMap) {
		log.info("调用四要素认证接口参数：{}", elements.toString());
		Map map = super.getRspMap(SystemConstant.RSPCODE_ERROR, null, null);
		
		/*校验是否已经验证过*/
		App_Log_Four_ElementsEntity logFourElem = checkValidated(elements);
		if(logFourElem != null){
			/*已经验证*/
			if (FOURELEMENTS_AUTH_CODE_SUCCESS.equals(logFourElem.getRsp_code())) {
				map = getRspMap(SystemConstant.RSPCODE_SUCCESS, logFourElem.getRsp_msg(), null);
			}
			return map;
		}
		String postResult = null;
		/*请求接口*/
		try {
			/*获取请求参数*/
			Map<String, String[]> params = getRequestParams(elements);
			if (URL.startsWith("https")) {
				postResult = post(URL + mapToUrlParam(params), null, PATHFLAT_HTTPS);
			} else {
				postResult = post(URL + mapToUrlParam(params), null, PATHFLAT_HTTP);
			}
			log.info("调用四要素认证接口返回内容：" + postResult);
		} catch (Exception e) {
			log.error("LogFourElementsService queryFourElement error:", e);
		}
		/*入库操作*/
		App_Log_Four_ElementsEntity logFour = addLogFourElements(elements, postResult, paramMap);
		if (FOURELEMENTS_AUTH_CODE_SUCCESS.equals(logFour.getRsp_code())) {
			map = getRspMap(SystemConstant.RSPCODE_SUCCESS, logFour.getRsp_msg(), null);
		}
		map.put(SystemConstant.RSP_MSG, logFour.getRsp_msg());
		return map;
	}

	@Override
	public Map queryFourElementResult(String orderNo, Map paramMap) {
		return null;
	}
	
	/**
	 * 查询是否已经验证过
	 * @param elements
	 * @return
	 */
	private App_Log_Four_ElementsEntity checkValidated(FourElements elements){
		Map<String, String> fourMap = new HashMap<String, String>();
		fourMap.put("PHONE", elements.getPhone());
		fourMap.put("NAME", elements.getName());
		fourMap.put("CERTIFICATE_NO", elements.getCertificateNo());
		fourMap.put("ACCT_NO", elements.getAccountNo());
		fourMap.put("RSP_CODE", FOURELEMENTS_AUTH_CODE_SUCCESS);
		//判断是否已经查询过该数据
		App_Log_Four_ElementsEntity logFourElem = super.getByMap(fourMap);
		return logFourElem;
	}
	
	/**
	 * 组装请求参数
	 * @param elements
	 * @return
	 * @throws Exception
	 */
	private Map<String, String[]> getRequestParams(FourElements elements) throws Exception{
		Map<String, String[]> params = new HashMap<String, String[]>();
		params.put("name", new String[] { elements.getName() });// 姓名
		params.put("idcard", new String[] { elements.getCertificateNo() });// 身份证
		params.put("phoneno", new String[] { elements.getPhone() });// 手机号码
		params.put("acctno", new String[] { elements.getAccountNo() });// 银行卡
		params.put("token", new String[] { TOKEN });
		params.put("timestamp", new String[] { DateUtil.getCurrDateTimeStr()});
		params.put("sign", new String[] { signTopRequest(params, ENCRYPTKEY) });
		return params;
	}
	
	/**
	 * 保存四要素请求记录
	 * @param elements
	 * @param result
	 * @param paramMap
	 * @return
	 */
	private App_Log_Four_ElementsEntity addLogFourElements(FourElements elements, String result, Map paramMap){
		/*基本信息*/
		App_Log_Four_ElementsEntity appLogFourElementsEntity = new App_Log_Four_ElementsEntity();
		appLogFourElementsEntity.setLoc_trace_no(String.valueOf(System.currentTimeMillis()) + IDFactoryUtil.getSixRandom()); 
		appLogFourElementsEntity.setIns_uuid(elements.getInsUUid());
		appLogFourElementsEntity.setName(elements.getName());
		appLogFourElementsEntity.setPhone(elements.getPhone());
		appLogFourElementsEntity.setCertificate_no(elements.getCertificateNo());
		appLogFourElementsEntity.setAcct_no(elements.getAccountNo());
		appLogFourElementsEntity.setRec_upd_usr_id(String.valueOf(paramMap.get(SystemConstant.SESSION_LOGIN_USER)));
		/*渠道返回信息*/
		if(StringUtils.isNotBlank(result)){
			JSONObject json = JSONObject.parseObject(result);
			if(json != null && !json.isEmpty()){
				appLogFourElementsEntity.setRsp_code(json.getString("code"));
				appLogFourElementsEntity.setRsp_msg(json.getString("codeMsg"));
				String responseDate = json.getString("responseDate");
				/*记录响应日期和时间*/
				if(StringUtils.isNotBlank(responseDate) && responseDate.length() == 14){
					appLogFourElementsEntity.setRsp_dt(responseDate.substring(0, 8));
					appLogFourElementsEntity.setRsp_ts(responseDate.substring(8));
				}
				/*记录返回流水号*/
				Object jsonResultObj =  json.getString("jsonResult");
				if(jsonResultObj != null && !String.valueOf(jsonResultObj).equals("")){
					JSONObject jsonResult = json.getJSONObject("jsonResult");
					if(jsonResult != null && !jsonResult.isEmpty()){
						appLogFourElementsEntity.setChannel_trace_no(jsonResult.getString("recordId"));
					}
				}
				
			}
		}else{
			appLogFourElementsEntity.setRsp_msg("四要素查询参数错误");
		}
		super.saveFourElementsEntity(appLogFourElementsEntity);
		return appLogFourElementsEntity;
	}

	/**
	 * 
	 * @param URL:请求地址
	 * @param params：请求参数
	 * @param pathFlat：1为http请求，2为https请求
	 * @return 返回json格式字符串
	 */
	@SuppressWarnings("deprecation")
	private String post(String URL, Map<String, String> params, int pathFlat)
			throws NoSuchAlgorithmException, KeyManagementException {
		// logger.info("POST请求，url：" + URL + "，Map参数：" + params.toString());
		/**
		 * 读取param中的数据，写入NameValuePair
		 */
		List<NameValuePair> nvps = new ArrayList<NameValuePair>();
		if (params != null) {
			Iterator<Entry<String, String>> iter = params.entrySet().iterator();
			while (iter.hasNext()) {
				Entry<String, String> entry = iter.next();
				String key = (String) entry.getKey();
				String value = (String) entry.getValue();

				nvps.add(new BasicNameValuePair(key, value));
			}
		}
		StringBuffer result = new StringBuffer();
		HttpClient httpClient = null;
		try {
			/**
			 * httpclient并发送post数据
			 */
			if (pathFlat == 2) {
				SSLContext ctx = SSLContext.getInstance("TLS");
				X509TrustManager tm = new X509TrustManager() {
					public X509Certificate[] getAcceptedIssuers() {
						return null;
					}

					public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
					}

					public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
					}
				};
				ctx.init(null, new TrustManager[] { tm }, null);
				SSLSocketFactory ssf = new SSLSocketFactory(ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
				SchemeRegistry registry = new SchemeRegistry();
				registry.register(new Scheme("https", 443, ssf));
				ThreadSafeClientConnManager mgr = new ThreadSafeClientConnManager(registry);
				httpClient = new DefaultHttpClient(mgr);
			} else if (pathFlat == 1) {
				httpClient = new DefaultHttpClient();
			}

			// HttpClient httpClient = new DefaultHttpClient();
			HttpParams httpParams = httpClient.getParams();
			HttpConnectionParams.setConnectionTimeout(httpParams, TIMEOUT); // 设定12秒超时，届时会弹出Exception
			HttpConnectionParams.setSoTimeout(httpParams, TIMEOUT);

			org.apache.http.client.methods.HttpPost httpPost = new org.apache.http.client.methods.HttpPost(URL);
			httpPost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
			HttpResponse response = httpClient.execute(httpPost);
			URL = URLDecoder.decode(URL, "UTF-8");
			/**
			 * 获取服务器响应
			 */
			HttpEntity entity = response.getEntity();
			InputStream in = entity.getContent();
			BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
			String line = "";
			while ((line = bufferedReader.readLine()) != null) {
				result.append(line);
			}
			in.close();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace(); // To change body of catch statement use File |
									// Settings | File Templates.
		} catch (ClientProtocolException e) {
			e.printStackTrace(); // To change body of catch statement use File |
									// Settings | File Templates.
		} catch (IOException e) {
			e.printStackTrace(); // To change body of catch statement use File |
									// Settings | File Templates.
		}
		return result.toString();
	}

	/**
	 * 把一个map对象转化为?开头的url参数字符串
	 * 
	 * @param params
	 * @return
	 */
	private String mapToUrlParam(Map<String, String[]> params) {
		StringBuffer result = new StringBuffer();
		for (Map.Entry<String, String[]> entry : params.entrySet()) {
			if (!StringUtils.isBlank(entry.getValue()[0])) {
				if (result.length() == 0) {// 第一个参数前面是?
					result.append("?" + entry.getKey() + "=" + entry.getValue()[0]);
				} else {
					result.append("&" + entry.getKey() + "=" + entry.getValue()[0]);
				}
			}
		}
		return result.toString();
	}

	/**
	 * 接口除sign字段所有参数加密md5
	 * 
	 * @param params
	 *            参数列表
	 * @param secret
	 *            加密秘钥
	 * @return
	 * @throws IOException
	 */
	private String signTopRequest(Map<String, String[]> params, String secret) throws IOException {
		// 第一步：检查参数是否已经排序
		String[] keys = params.keySet().toArray(new String[0]);
		Arrays.sort(keys);

		// 第二步：把所有参数名和参数值串在一起
		StringBuilder query = new StringBuilder(secret);
		for (String key : keys) {
			String[] values = params.get(key);
			String v = "";
			if (values != null && values.length != 0) {
				String encoding = getEncoding(values[0]);
				if ("ISO-8859-1".equalsIgnoreCase(encoding)) {
					v = convert(values[0]);
				} else {
					v = values[0];
				}
			}
			if ("sign".equals(key)) {
				continue;
			}
			if (areNotBlank(key, v)) {
				query.append(key).append(v);
			}
		}
		query.append(secret);
		// 第三步：使用MD5加密
		byte[] bytes = encryptMD5(query.toString());

		// 第四步：把二进制转化为大写的十六进制
		String hexMd5 = byte2hex(bytes);
		return hexMd5;
	}

	/**
	 * 获取编码后的字符串
	 * 
	 * @param str
	 * @return
	 */
	private String getEncoding(String str) {
		String encode = "GB2312";
		try {
			if (str.equals(new String(str.getBytes(encode), encode))) {
				String s = encode;
				return s;
			}
		} catch (Exception exception) {
		}
		encode = "ISO-8859-1";
		try {
			if (str.equals(new String(str.getBytes(encode), encode))) {
				String s1 = encode;
				return s1;
			}
		} catch (Exception exception1) {
		}
		encode = "UTF-8";
		try {
			if (str.equals(new String(str.getBytes(encode), encode))) {
				String s2 = encode;
				return s2;
			}
		} catch (Exception exception2) {
		}
		encode = "GBK";
		try {
			if (str.equals(new String(str.getBytes(encode), encode))) {
				String s3 = encode;
				return s3;
			}
		} catch (Exception exception3) {
		}
		return "";
	}

	/**
	 * 检查指定的字符串列表是否不为空
	 * 
	 * @param values
	 * @return
	 */
	public boolean areNotBlank(String... values) {
		boolean result = true;
		if (values == null || values.length == 0) {
			result = false;
		} else {
			for (String value : values) {
				result &= !StringUtils.isBlank(value);
			}
		}
		return result;
	}

	/**
	 * md5加密，适用该操作
	 *
	 * @param data
	 * @return
	 * @throws IOException
	 */
	private byte[] encryptMD5(String data) throws IOException {
		byte[] bytes = null;
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
			bytes = md.digest(data.getBytes("UTF-8"));
		} catch (GeneralSecurityException gse) {
			String msg = getStringFromException(gse);
			throw new IOException(msg);
		}
		return bytes;
	}

	/**
	 * 转换位
	 * 
	 * @param bytes
	 * @return
	 */
	private static String byte2hex(byte[] bytes) {
		StringBuilder sign = new StringBuilder();
		for (int i = 0; i < bytes.length; i++) {
			String hex = Integer.toHexString(bytes[i] & 0xFF);
			if (hex.length() == 1) {
				sign.append("0");
			}
			sign.append(hex.toUpperCase());
		}
		return sign.toString();
	}

	/**
	 * 获取异常信息
	 * 
	 * @param e
	 * @return
	 */
	private static String getStringFromException(Throwable e) {
		String result = "";
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		PrintStream ps = new PrintStream(bos);
		e.printStackTrace(ps);
		try {
			result = bos.toString("UTF-8");
		} catch (IOException ioe) {
		}
		return result;
	}

	/**
	 * 转换编码
	 * 
	 * @param target
	 * @return
	 */
	public static String convert(String target) {
		if (StringUtils.isBlank(target)) {
			return "";
		}
		try {
			return new String(target.trim().getBytes("ISO-8859-1"), "UTF-8");
		} catch (UnsupportedEncodingException e) {
			return target;
		}
	}

}
